#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdint.h>

#include "Estructuras.h"
#include "includes/Mensajes.h"
#include "includes/Threads.h"
#include "list.h"


extern stRaidData raidDataGlobal;

/*
 * @NAME: crearSenial
 * @DESC: devuelve una se�al creada con signalfd que se enmascara en un socket
 * */
int crearSenial(int _senial)
{
	sigset_t mask;
	int senialRet;
	
	/* sigemptyset() Vacia la m�scara: pone la m�scara a 0 */
	sigemptyset (&mask);
	
	/* sigaddset() A�ade la se�al a la m�scara */
	sigaddset (&mask, _senial);
	
	/*TODO no se si hace falta!!! Block the signals thet we handle using signalfd(), so they don't
	 * cause signal handlers or default signal actions to execute. */	
	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) 
	{
		perror ("sigprocmask");
		return 1;
	}


 	/* signalfd() Create a file descriptor from which we will read the signals */
	
	senialRet = signalfd (-1, &mask, 0);
	if (senialRet < 0) 
	{
		perror ("error creando signalfd()");
		return 1;
	}
	return senialRet;
}

/*
 * @NAME: startEspejar
 * @DESC: enviar tantos send al PPD como sectores tenga el disco*/
int startEspejar(int socketPPD)
{
	int i;
	stPedido pedido;
	stMsgNIPC mensaje;

	mensaje.PayloadDescriptor = MSG_GET_SECTOR;
	if(mensaje.Payload = malloc(sizeof(uint32_t)) == NULL) return EXIT_ERROR_MEMORY;

	for(i = 0; i<raidDataGlobal.totalSectores ; i++)
	{
		/* TODO en el mensaje voy pidiendo cada sector = i del disco */

		/* Seteo el socket del pedido a cero para indicar
		 * que no es un pedido del FS*/
		enviarMensaje(socketPPD, &mensaje);
	}
	return EXIT_SUCCESS;
}


/*
 * @NAME: processQueueMirror
 * @DESC: por cada nodo de la QueueMirror envia un send al PPD
 * 		 	y elimina el mismo de la cola.
 * */
int processQueueMirror(int socketPPD)
{
	/* Envio al PPD los pedidos de la QueueMirror: estoy grabando en este nuevo PPD los sectores
	 * que tienen todos los discos */
	int i, size;
	stPedido* pedido;
	stMsgNIPC mensaje;

	if(mensaje.Payload = malloc(sizeof(uint32_t)) == NULL) return EXIT_ERROR_MEMORY;

	size =  collection_list_size(raidDataGlobal.QueueMirror);

	for(i = 0; i< size; i++)
	{
		pedido = (stPedido*)collection_list_get(raidDataGlobal.QueueMirror, i);
		armarMensajeFromPedido(&mensaje, pedido);
		enviarMensaje(socketPPD, &mensaje);
	}

	/* Dejo limpia la lista para la prox vez que necesite espejar */
	collection_list_clean(raidDataGlobal.QueueMirror, NULL);

	return EXIT_SUCCESS;
}


int processQueueWrite(t_list *QueueWrites, int socketPPD)
{
	int i, size;
	stPedido* pedidoWrite;
	stMsgNIPC mensaje;

	if(mensaje.Payload = malloc(sizeof(uint32_t)) == NULL) return EXIT_ERROR_MEMORY;

	size = collection_list_size(QueueWrites);

	/* Recorro la lista y por cada nodo con estaro READY
	 * envio mensaje el PPD y seteo el estado a RUNNING */
	for(i = 0; i< size; i++)
	{
		pedidoWrite = (stPedido *) collection_list_get(QueueWrites, i);

		if(pedidoWrite->state == STATE_READY)
		{
			armarMensajeFromPedido(&mensaje, pedidoWrite);

			enviarMensaje(socketPPD, &mensaje);

			pedidoWrite->state = STATE_RUNNING;
		}
	}
	return EXIT_SUCCESS;
}

int processQueueRead(t_list *QueueReads, int socketPPD)
{
	int i, size;
	stPedido* pedidoRead;
	stMsgNIPC mensaje;

	if(mensaje.Payload = malloc(sizeof(uint32_t)) == NULL) return EXIT_ERROR_MEMORY;
	size = collection_list_size(QueueReads);

	/* Recorro la lista y por cada nodo con estaro READY
	 * envio mensaje el PPD y seteo el estado a RUNNING */
	for(i = 0; i< size; i++)
	{
		pedidoRead = (stPedido *) collection_list_get(QueueReads, i);

		if(pedidoRead->state == STATE_READY)
		{
			armarMensajeFromPedido(&mensaje, pedidoRead);

			enviarMensaje(socketPPD, &mensaje);

			pedidoRead->state = STATE_RUNNING;
		}
	}
	return EXIT_SUCCESS;
}
